import java.io.*;
import java.util.Scanner;

public class CacheSimulator 
{

    /**
     * @param args
     */
    public static void main(String[] args) throws IOException 
    {
        File inputFile = new File(args[0]);
        String stats, outFile;
        String[] allCache = new String[3];
        String[] allBlock = new String[3];
        String[] allAssoc = new String[3];
        String[] allReplace = new String[3];
        String[] allWritePolicy = new String[2];
        String[] parms = new String[6];

        //flag for complete output
        boolean runAll = false;
        
        if(args[1].toLowerCase().equals("all"))
        {
            runAll = true;
            allCache = new String[] {"512","1024","2048"};
            allBlock = new String[] {"4","8","16"};
            allAssoc = new String[] {"1","2","4"};
            allReplace = new String[] {"R","FIFO","LRU"};
            allWritePolicy = new String[] {"wb","wt"};
        }
        
        //this is the output...
        //all but the close need to be before the run loop
        String extension = args[0].substring(args[0].length()-4);
        String name = args[0].substring(0, args[0].length()-4);

        //need logic to control filenames
        if(runAll)
            outFile = (name.toUpperCase() + "_ALL" + extension.toUpperCase());
        else
            outFile = name + " (" + args[1] + "CS_" + args[2] + "BS_" +
                    args[3] + "_" + args[4] + ")" + extension;
        
        BufferedWriter out = new BufferedWriter(new FileWriter(outFile));
        
        if(runAll)
        {
            for(int rint = 0; rint < allReplace.length; ++rint)
            {
                for(int wint = 0; wint < allWritePolicy.length; ++wint)
                {
                    for(int cint = 0; cint < allCache.length; ++cint)
                    {
                        for(int bint = 0; bint < allBlock.length; ++bint)
                        {
                            for(int aint = 0; aint < allAssoc.length; ++aint)
                            {
                                //out.write("Replacement: " + allReplace[rint]);
                                //out.write("\tWrite: " + allWritePolicy[wint]);
                                //out.write("\tCache: " + allCache[cint]);
                                //out.write("\tBlock: " + allBlock[bint]);
                                //out.write("\tAssoc: " + allAssoc[aint]);
                                
                                parms[0] = args[0];
                                parms[1] = allCache[cint];
                                parms[2] = allBlock[bint];
                                parms[3] = allAssoc[aint];
                                parms[4] = allReplace[rint];
                                parms[5] = allWritePolicy[wint];
                                
                                stats = run(parms, inputFile);
                                out.write(stats);
                            }
                            out.write("++++++\n");
                        }
                        out.write("++++++\n");
                    }
                    out.write("++++++\n");
                }
                out.write("++++++\n");
            }
            out.write("++++++\n");
            
        }
        else
        {
            stats = run(args, inputFile);
            out.write(stats);
        }
        
        out.close();

    }
    
    public static String run(String[] parms, File inputFile) throws IOException
    {
        
        Scanner scanner = new Scanner(new FileInputStream(inputFile));

        int blockSize = Integer.parseInt(parms[2]);
        int cacheSize = Integer.parseInt(parms[1]);
        int numBlocks = cacheSize / blockSize;

        int assoc = Integer.parseInt(parms[3]);
        String replacementPolicy = parms[4];
        String writePolicy = parms[5];

        Cache cache = new Cache(numBlocks, blockSize, assoc, 
                replacementPolicy, writePolicy);

        while(scanner.hasNextLine())
        {
            String input = scanner.nextLine();
            long address = Long.parseLong(input.substring(2), 16);
            char op = input.charAt(0);
            if(op == 'R')
                cache.read(address);
            else if(op == 'W')
                cache.write(address);
        }
        
        scanner.close();

        return cache.getStats(cacheSize, assoc, 
                replacementPolicy);
    }
}
